/**
 * Copyright (C) 2010 David Simonek <dafesimonek@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * PlaylistPanel.java
 *
 * Created on Aug 6, 2010, 9:29:04 PM
 */

package org.dafe.partyband.gui.concerts;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.Collections;
import javax.swing.Action;
import javax.swing.JLabel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.dafe.partyband.db.api.IConcert;
import org.dafe.partyband.db.api.ISong;
import org.dafe.partyband.db.api.ISongResource;
import org.dafe.partyband.gui.AbstractSongTableModel;
import org.dafe.partyband.gui.Utilities;
import org.dafe.partyband.gui.Utilities.CustomColumnFactory;
import org.dafe.partyband.gui.songs.ActionsFactory;
import org.dafe.partyband.importer.api.IImporterServices;
import org.dafe.partyband.importer.api.IMimeTypeDetector;
import org.jdesktop.swingx.color.ColorUtil;
import org.jdesktop.swingx.decorator.*;
import org.jdesktop.swingx.renderer.LabelProvider;
import org.jdesktop.swingx.renderer.StringValue;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;

/**
 *
 * @author dafe
 */
public class PlaylistPanel extends javax.swing.JPanel {

    private static final IMimeTypeDetector mimeDetector = Lookup.getDefault().lookup(IImporterServices.class).getMimeDetector();

    private final IConcert concert;
    private final PlaylistModel playlistModel;
    private final InstanceContent selSongContent;
    private final Lookup selSongLkp;
    private final Action moveUpAction;
    private final Action moveDownAction;
    private final Action addAction;
    private final Action deleteAction;
    private final Action openTextAction;
    private final InstanceContent selSongsResourcesContent;
    private final AbstractLookup selSongsResourcesLkp;
    private final Action exportAction;
    private final Action playMp3Action;
    private final Action printAction;
    private final Action printPlaylistAction;
    private final InstanceContent selSongTextsContent;
    private final AbstractLookup selSongTextsLkp;

    /** Creates new form PlaylistPanel */
    public PlaylistPanel(final IConcert concert) {
        this.concert = concert;
        initComponents();

        selSongContent = new InstanceContent();
        selSongLkp = new AbstractLookup(selSongContent);
        
        selSongsResourcesContent = new InstanceContent();
        selSongsResourcesLkp = new AbstractLookup(selSongsResourcesContent);

        selSongTextsContent = new InstanceContent();
        selSongTextsLkp = new AbstractLookup(selSongTextsContent);
        
        addAction = ConcertActionsFactory.createAddAction(concert, this);
        moveUpAction = ConcertActionsFactory.createMoveSongAction(
                NbBundle.getMessage(ConcertActionsPanel.class, "ACT_MoveUp"),
                NbBundle.getMessage(ConcertActionsPanel.class, "HINT_MoveUp"),
                concert, this, selSongLkp, -1);
        moveDownAction = ConcertActionsFactory.createMoveSongAction(
                NbBundle.getMessage(ConcertActionsPanel.class, "ACT_MoveDown"),
                NbBundle.getMessage(ConcertActionsPanel.class, "HINT_MoveDown"),
                concert, this, selSongLkp, 1);
        deleteAction = ConcertActionsFactory.createDeleteSongAction(concert, this, selSongLkp);
        
        exportAction = ConcertActionsFactory.createExportSongAction(selSongsResourcesLkp);

        playlistTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        playlistTable.setHighlighters(HighlighterFactory.createSimpleStriping());

        playlistTable.getActionMap().put("AddSongsAction", addAction);
        playlistTable.getInputMap().put(KeyStroke.getKeyStroke(
                KeyEvent.VK_INSERT, 0), "AddSongsAction");

        playlistTable.getActionMap().put("MoveUpAction", moveUpAction);
        playlistTable.getInputMap().put(KeyStroke.getKeyStroke(
                KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK), "MoveUpAction");
        
        playlistTable.getActionMap().put("MoveDownAction", moveDownAction);
        playlistTable.getInputMap().put(KeyStroke.getKeyStroke(
                KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK), "MoveDownAction");

        playlistTable.getActionMap().put("DeleteSongAction", deleteAction);
        playlistTable.getInputMap().put(KeyStroke.getKeyStroke(
                KeyEvent.VK_DELETE, 0), "DeleteSongAction");

        openTextAction = ActionsFactory.createOpenTextSongAction(selSongLkp);
        playlistTable.getActionMap().put("OpenTextAction", openTextAction);
        playlistTable.getInputMap().put(KeyStroke.getKeyStroke(
                KeyEvent.VK_ENTER, 0), "OpenTextAction");

        playMp3Action = ActionsFactory.createPlayMp3SongAction(selSongLkp);
        playlistTable.getActionMap().put("PlayMp3Action", playMp3Action);
        playlistTable.getInputMap().put(KeyStroke.getKeyStroke(
                KeyEvent.VK_SPACE, 0), "PlayMp3Action");
        
        printAction = ActionsFactory.createPrintMaterialsAction(
                selSongTextsLkp,
                NbBundle.getMessage(ConcertActionsPanel.class, "ACT_PrintSelected"),
                NbBundle.getMessage(ConcertActionsPanel.class, "HINT_PrintSelected"));
        
        printPlaylistAction = ConcertActionsFactory.createPrintPlaylistAction(concert, this);

        // define column features and properties
        CustomColumnFactory customCF = new Utilities.CustomColumnFactory();
        CustomColumnFactory.ColumnDescription orderColumn = new CustomColumnFactory.ColumnDescription();
        orderColumn.prototypeDescription = new CustomColumnFactory.PrototypeDescription(
                String.valueOf(concert.getSongs().size()) + " . ", 0.5f, 1.5f);
        orderColumn.componentProvider = new LabelProvider(JLabel.CENTER);
        customCF.setColumnDescription(columnIds[0], orderColumn);

        playlistTable.setColumnFactory(customCF);
        
        final Color playedFirstC = ColorUtil.interpolate(Color.green, playlistTable.getBackground(), 0.15f);
        HighlightPredicate playedFirstPredicate = new HighlightPredicate() {
            public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
                int modelRow = adapter.convertRowIndexToModel(adapter.row);
                return ConcertUtils.isPlayedFirst(concert.getSongs().get(modelRow), concert);
            }
        };
        ColorHighlighter playedFirstH = new ColorHighlighter(playedFirstPredicate, playedFirstC, null);
        playlistTable.addHighlighter(playedFirstH);
        
        ToolTipHighlighter playedFirstTooltipH = new ToolTipHighlighter(
                playedFirstPredicate, new StringValue() {
            public String getString(Object value) {
                return NbBundle.getMessage(ConcertActionsPanel.class, "HINT_PlayedFirst");
            }
        });
        playlistTable.addHighlighter(playedFirstTooltipH);
        
        final Color withoutTextC = ColorUtil.interpolate(Color.red, playlistTable.getBackground(), 0.2f);
        
        HighlightPredicate withoutTextPredicate = new HighlightPredicate() {
            public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
                int modelRow = adapter.convertRowIndexToModel(adapter.row);
                return Utilities.getTextWithChords(concert.getSongs().get(modelRow)) == null;
            }
        };
        ColorHighlighter withoutTextH = new ColorHighlighter(withoutTextPredicate, withoutTextC, null);
        playlistTable.addHighlighter(withoutTextH);
        
        ToolTipHighlighter withoutTextTooltipH = new ToolTipHighlighter(
                withoutTextPredicate, new StringValue() {
            public String getString(Object value) {
                return NbBundle.getMessage(ConcertActionsPanel.class, "HINT_WithoutText");
            }
        });
        playlistTable.addHighlighter(withoutTextTooltipH);

        playlistModel = new PlaylistModel();
        playlistTable.setModel(playlistModel);
        playlistTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                selSongContent.set(Collections.EMPTY_LIST, null);
                for (ISong song : Utilities.getSelectedSongs(playlistTable, playlistModel)) {
                    selSongContent.add(song);
                }
                
                selSongsResourcesContent.set(Collections.EMPTY_LIST, null);
                selSongTextsContent.set(Collections.EMPTY_LIST, null);
                for (ISongResource songRes : Utilities.getSelectedResources(playlistTable, playlistModel)) {
                    selSongsResourcesContent.add(songRes);
                    ISong parentSong = songRes.getParent();
                    if (parentSong != null) {
                        if (songRes.equals(Utilities.getPreferredResourceOfType(parentSong, 
                                IMimeTypeDetector.ContentType.TEXT_WITH_CHORDS))) {
                            selSongTextsContent.add(songRes);
                        }
                    }
                }
                
            }
        });

    }

    public Lookup getSelSongLookup () {
        return selSongLkp;
    }

    public Lookup getSelResourcesLookup () {
        return selSongsResourcesLkp;
    }
    
    public Lookup getSelSongTextsLookup () {
        return selSongTextsLkp;
    }

    public void refresh () {
        playlistModel.refresh();
    }

    public void setSelectedIndex (int index) {
        playlistTable.setRowSelectionInterval(index, index);
    }

    private void showPopupMenu(MouseEvent evt) {
        if (!evt.isPopupTrigger()) {
            return;
        }
        Utilities.assureSelected(playlistTable, evt.getPoint());

        JPopupMenu popup = new JPopupMenu();


        Utilities.addAction2Popup(popup, openTextAction);
        Utilities.addAction2Popup(popup, playMp3Action);
        int popupItemsCount = popup.getSubElements().length;
        if (popupItemsCount > 0) {
            popup.add(new JSeparator());
            popupItemsCount = popup.getSubElements().length;
        }
        Utilities.addAction2Popup(popup, addAction);
        Utilities.addAction2Popup(popup, deleteAction);
        if (popup.getSubElements().length > popupItemsCount) {
            popup.add(new JSeparator());
            popupItemsCount = popup.getSubElements().length;
        }
        Utilities.addAction2Popup(popup, moveUpAction);
        Utilities.addAction2Popup(popup, moveDownAction);
        if (popup.getSubElements().length > popupItemsCount) {
            popup.add(new JSeparator());
        }
        Utilities.addAction2Popup(popup, exportAction);
        Utilities.addAction2Popup(popup, printAction);
        Utilities.addAction2Popup(popup, printPlaylistAction);
        
        popup.add(new JSeparator());
        Utilities.addMusicServices2Popup(popup, selSongLkp);

        popup.show(playlistTable, evt.getX(), evt.getY());
    }

    public JTable getPlaylistTable() {
        return playlistTable;
    }

    private static final String[] columnIds = {"positionColumn", "songAuthorColumn"};

    private class PlaylistModel extends AbstractSongTableModel {

        @Override
        public String getColumnName(int column) {
            return columnIds[column];
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return String.class;
        }

        public int getRowCount() {
            return concert.getSongs().size();
        }

        public int getColumnCount() {
            return 2;
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            if (columnIndex == 0) {
                return (rowIndex + 1) + ".";
            }
            ISong song = concert.getSongs().get(rowIndex);
            // html text coloring doesn't work OK when scrolling through the table, unfortunately
            //return song != null ? "<html>" + song.getName() + ", <i>" + song.getAuthor().getName() + "</i></html>" : "deleted";
            return song != null ? song.getName() + ", " + song.getAuthor().getName() : "deleted";
        }

        public void refresh() {
            fireTableDataChanged();
        }

        @Override
        public ISong getSongAtRow(int index) {
            return concert.getSongs().get(index);
        }

    }


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        playlistTable = new org.jdesktop.swingx.JXTable();
        actionsPane = new org.jdesktop.swingx.JXCollapsiblePane();

        setLayout(new java.awt.BorderLayout());

        playlistTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
        playlistTable.setShowHorizontalLines(false);
        playlistTable.setShowVerticalLines(false);
        playlistTable.setTableHeader(null);
        playlistTable.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                playlistTableMouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                playlistTableMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                playlistTableMouseReleased(evt);
            }
        });
        jScrollPane1.setViewportView(playlistTable);

        add(jScrollPane1, java.awt.BorderLayout.CENTER);
        add(actionsPane, java.awt.BorderLayout.LINE_END);
    }// </editor-fold>//GEN-END:initComponents

    private void playlistTableMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_playlistTableMousePressed
        showPopupMenu(evt);
    }//GEN-LAST:event_playlistTableMousePressed

    private void playlistTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_playlistTableMouseClicked
        if (evt.getClickCount() == 2) {
            if (openTextAction.isEnabled()) {
                openTextAction.actionPerformed(null);
            }
        }
    }//GEN-LAST:event_playlistTableMouseClicked

    private void playlistTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_playlistTableMouseReleased
        showPopupMenu(evt);
    }//GEN-LAST:event_playlistTableMouseReleased


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private org.jdesktop.swingx.JXCollapsiblePane actionsPane;
    private javax.swing.JScrollPane jScrollPane1;
    private org.jdesktop.swingx.JXTable playlistTable;
    // End of variables declaration//GEN-END:variables

}
